﻿using System.Collections.Generic;

using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// Very simple sprite animation. Attach to a sprite and specify a common prefix such as "idle" and it will cycle through them.
/// </summary>

[ExecuteInEditMode]
[RequireComponent(typeof(Image))]
public class UGUISpriteAnimation : MonoBehaviour
{
	[HideInInspector][SerializeField] protected int mFPS = 30;
	[HideInInspector][SerializeField] protected string mPrefix = "";
    [HideInInspector][SerializeField] protected string mIndexes = "";
    [HideInInspector][SerializeField] protected bool mLoop = true;
	[HideInInspector][SerializeField] protected bool mSnap = true;
    [HideInInspector][SerializeField] protected List<Sprite> sprites = new List<Sprite>();

    protected Image image;
	protected float mDelta = 0f;
	protected int mIndex = 0;
	protected bool mActive = true;

    protected int[] mCachedIndexes;

    /// <summary>
    /// Number of frames in the animation.
    /// </summary>

    public int frames { get { return sprites.Count; } }

	/// <summary>
	/// Animation framerate.
	/// </summary>

	public int framesPerSecond { get { return mFPS; } set { mFPS = value; } }

	/// <summary>
	/// Set the animation to be looping or not
	/// </summary>

	public bool loop { get { return mLoop; } set { mLoop = value; } }

	/// <summary>
	/// Returns is the animation is still playing or not
	/// </summary>

	public bool isPlaying { get { return mActive; } }

	/// <summary>
	/// Rebuild the sprite list first thing.
	/// </summary>

	protected virtual void Start ()
    {
        if (image == null) image = GetComponent<Image>();

        RebuildIndexes();
    }

    protected virtual void RebuildIndexes()
    {
        mIndex = 0;

        mCachedIndexes = null;

        if (!string.IsNullOrEmpty(mIndexes))
        {
            string[] parsedIndexes = mIndexes.Split(new char[] { ',' }, System.StringSplitOptions.RemoveEmptyEntries);

            if(parsedIndexes.Length > 0)
            {
                int[] indexes = new int[parsedIndexes.Length];

                for (int i = 0; i < parsedIndexes.Length; i++)
                {
                    indexes[i] = int.Parse(parsedIndexes[i]);
                }

                mCachedIndexes = indexes;
            }
        }
    }

	/// <summary>
	/// Advance the sprite animation process.
	/// </summary>

	protected virtual void Update ()
	{
		if (mActive && sprites.Count > 1 && Application.isPlaying && mFPS > 0)
		{
			mDelta += Time.unscaledDeltaTime;
			float rate = 1f / mFPS;

			if (rate < mDelta)
			{
				mDelta = (rate > 0f) ? mDelta - rate : 0f;

                int index;

                if (mCachedIndexes != null)
                {
                    if (++mIndex >= mCachedIndexes.Length)
                    {
                        mIndex = 0;
                        mActive = mLoop;
                    }

                    index = mCachedIndexes[mIndex];
                }
                else
                {
                    if (++mIndex >= sprites.Count)
                    {
                        mIndex = 0;
                        mActive = mLoop;
                    }

                    index = mIndex;
                }

				if (mActive)
				{
					image.sprite = sprites[index];
					if (mSnap) image.SetNativeSize();
				}
			}
		}
	}
	
	/// <summary>
	/// Reset the animation to the beginning.
	/// </summary>

	public void Play () { mActive = true; }

	/// <summary>
	/// Pause the animation.
	/// </summary>

	public void Pause () { mActive = false; }

	/// <summary>
	/// Reset the animation to frame 0 and activate it.
	/// </summary>

	public void ResetToBeginning ()
	{
		mActive = true;
		mIndex = 0;

		if (image != null && sprites.Count > 0)
		{
			image.sprite = sprites[mIndex];
			if (mSnap) image.SetNativeSize();
		}
	}

    public void SetSprites(IEnumerable<Sprite> sprites)
    {
        this.sprites.Clear();
        this.sprites.AddRange(sprites);
    }

    public void SetIndexes(string indexes)
    {
        mIndexes = indexes;
        RebuildIndexes();
    }
}
